#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>

const int N = 10000;
class TreeType
{
private:
    std::string name;
    std::string color;
    std::string texture;
public:
    TreeType(std::string name_, std::string color_, std::string texture_)
    {
        name = name_;
        color = color_;
        texture = texture_;
        std::cout<<"create a TreeType..."<<std::endl;
    }
    void draw(int x, int y)
    {
        std::cout<<"draw tree "<<this<<" at "<<x<<" , "<<y<<std::endl;
    }
};

class Tree
{
    int x,y;
private:
    TreeType *treeType = nullptr;
public:
    Tree(int x_, int y_, TreeType* type)
    {
        x = x_;
        y = y_;
        treeType = type;
    }
    void draw()
    {
        treeType->draw(x,y);
    }
};

class TreeFactory
{
private:
    std::unordered_map<std::string, TreeType*> map;
public:
    TreeFactory()
    {

    }
    TreeType* getTreeType(std::string name, std::string color, std::string texture)
    {
        std::string key = name + color + texture;
        if(map.find(key) == map.end())
        {
            map[key] = new TreeType(name, color, texture);
        }
        return map[key];
    }
};

class Forest
{
private:
    TreeFactory* treeFactory;
    std::vector<Tree*> treelist;
public:
    Forest()
    {
        treeFactory = new TreeFactory();
    }
    void plantTree(int x, int y, std::string name, std::string color, std::string texture)
    {
        treelist.push_back(new Tree(x, y, treeFactory->getTreeType(name, color, texture)));
    }
    void draw()
    {
        for(auto tree : treelist)
        {
            tree->draw();
        }
    }
};

int main() {
    Forest forest;
    forest.plantTree(0, 1, "Tree1", "Red", "Texture1");
    forest.plantTree(1, 2, "Tree1", "Red", "Texture1");
    forest.plantTree(2, 3, "Tree1", "Red", "Texture2");
    forest.plantTree(3, 4, "Tree1", "Red", "Texture1");
    forest.plantTree(4, 5, "Tree1", "Red", "Texture1");
    forest.plantTree(5, 6, "Tree1", "Red", "Texture4");
    forest.plantTree(6, 7, "Tree1", "Red", "Texture1");
    forest.plantTree(7, 8, "Tree1", "Red", "Texture1");
    forest.draw();
    return 0;
}



